#include "VScintillaEx.h"
#include "VQscilexerCppAttach.h"
#include "VGlobal.h"
#include "VFunctions.h"
#include "VWords.h"
#include "VTranslate.h"
#include "VFile.h"

#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonDocument>
#include <QDebug>
#include <QKeyEvent>
#include <QFileInfo>

VScintillaEx::VScintillaEx(QWidget *parent) : VScintillaBase(parent),
    _modify(false)
{

    init_menu();
    init_setting();
    init_option();
    init_color();
    init_connect();

    this->installEventFilter(this);
    this->viewport()->installEventFilter(this);
}

VScintillaEx::VScintillaEx(QWidget *parent, QString path, QString text, int type) :
    VScintillaBase(parent),
    _modify(false),
    _content_menu(this),
    _expand_menu(this),
    _tip_timer(this),
    _update_timer(this)
{

    init_menu();
    init_setting();
    init_option();
    init_color();

    _path = path;
    _type = type;
    setText(text);
    on_linesChanged();
    this->setModified(false);

    this->setObjectName("scintilla");
    init_connect();

    this->installEventFilter(this);
    this->viewport()->installEventFilter(this);
}

void VScintillaEx::save()
{
    if(_modify)
    {
        set_modify(false);
        this->setModified(false);
        VFunctions::save_file(_path, this->text());
        _last_modify_time = VFunctions::file_last_modify_time(_path);
        emit signal_save_file(_path, this->text(), _type, _last_modify_time);
    }
}

bool VScintillaEx::save_question()
{
    if(_modify == false)
    {
        return true;
    }

    int result = QMessageBox::question(this, "保存更改", QFileInfo(_path).fileName() + +" 该文件被修改, 是否保存更改?",
            QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    if(result == QMessageBox::Cancel)
    {
        return false;
    }

    if(result == QMessageBox::Yes)
    {
        save();
    }
    else
    {
        emit signal_reload_file(_path);
    }

    return true;
}

void VScintillaEx::jump_request()
{
    int position = this->cursorPos();
    QString pre = get_line_text_of_pos_before(position);
    QString next = get_line_text_of_pos_next(position);
    int line = this->posOfLine(position);
    emit signal_jump_request(_path, pre, next, line +1, in_function(line));
}

void VScintillaEx::input_word(VWords *ptr)
{
    this->setFocus();
    if(ptr != nullptr)
    {
        qDebug() << ptr->_name;
        emit signal_select_word(_path, new VWords(ptr));

        // 删除当前提示的内容
        QString input= get_input_block();
        qDebug() << "input" << input;
        int input_length = input.toStdString().length();

        int cursor_pos = this->cursorPos();
        this->setSelect(cursor_pos - input_length, cursor_pos);
        this->replaceSelectedText("");
//                        VGlobal::input_tip->hide();

//                        return true;

        if(ptr->_kind == VWords::KIND::TEMPLATE)
        {
            int tab_count = this->indentation(this->cursorOfLine()) / this->tabWidth();
            qDebug() << tab_count;
            QString s_pre;
            while(tab_count--)
            {
                s_pre += '\t';
            }

            qDebug() << s_pre;
            QString s_template = ptr->_signature;
            s_template = s_template.replace("<br>", "\r\n" + s_pre);
            this->insert(s_template);
            this->findFirst("/\\*-.*?-\\*/", true, false, false, true);
            if(this->selectedText() == "/*--*/")
            {
                this->replaceSelectedText("");
            }

//                            VGlobal::input_tip->hide();
            emit signal_hide_tip(VGlobal::TipType::TIP_INPUT);
            return;
        }
        else
        {
            this->replaceSelectedText(ptr->_name);
//                            VGlobal::input_tip->hide();
            emit signal_hide_tip(VGlobal::TipType::TIP_INPUT);
            return;
        }
        delete ptr;
    }
}

void VScintillaEx::append_navigation()
{
    emit signal_append_navigation(_path, this->cursorOfLine(), this->cursorPos());
}

void VScintillaEx::init_menu()
{
    _expand_menu.setTitle("拓展");
    _expand_menu.setIcon(QIcon(VGlobal::icon_path.value("setting")));
    _expand_menu.addAction(VGlobal::action.value("foldAll"));
    _expand_menu.addAction(VGlobal::action.value("expandedAll"));
    _expand_menu.addSeparator();
    _expand_menu.addAction(VGlobal::action.value("code_format"));
    _expand_menu.addAction(VGlobal::action.value("search"));

}

void VScintillaEx::init_setting()
{
    // skin
    QJsonObject object;
    object = VFunctions::get_file_jsonDocument(VGlobal::skins_dir + "/" + VGlobal::setting.skin_name + "/scintilla.json").object();
    QJsonArray array = object.value("color").toArray();
    foreach(QJsonValue value, array)
    {
        QJsonObject object = value.toObject();
        QString name = object.value("name").toString();

        StyleData style;
        style.fore = object.value("fore").toString().toInt(nullptr, 16);
        style.back = object.value("back").toString().toInt(nullptr, 16);
        style.bold = object.value("fore").toString() == "true";
        style.italic = object.value("italic").toString() == "true";
        _style_map.insert(name, style);
    }
}

void VScintillaEx::init_color()
{
    // lexer 配色
    _vlexer.setPaper(_style_map.value("默认").back, -1);
    _vlexer.setFont(QFont(VGlobal::setting.textedit_font_name, VGlobal::setting.textedit_font_size));
    _vlexer.setColor(_style_map.value("关键字").fore, QsciLexerCPP::Keyword);
    _vlexer.setColor(_style_map.value("关键字").fore, QsciLexerCPP::KeywordSet2);
    _vlexer.setColor(_style_map.value("双引号块").fore, QsciLexerCPP::DoubleQuotedString);
    _vlexer.setColor(_style_map.value("单引号块").fore, QsciLexerCPP::SingleQuotedString);
    _vlexer.setColor(_style_map.value("预处理").fore, QsciLexerCPP::PreProcessor);
    _vlexer.setColor(_style_map.value("注释块").fore, QsciLexerCPP::Comment);
    _vlexer.setColor(_style_map.value("注释行").fore, QsciLexerCPP::CommentLine);
    _vlexer.setColor(_style_map.value("标识符").fore, QsciLexerCPP::Identifier);
    _vlexer.setColor(_style_map.value("操作符").fore, QsciLexerCPP::Operator);
    _vlexer.setColor(_style_map.value("数值").fore, QsciLexerCPP::Number);

    // 行号栏
    this->setMarginsFont(QFont(VGlobal::setting.textedit_font_name, VGlobal::setting.textedit_font_size));
    this->SendScintilla(QsciScintilla::SCI_STYLESETBACK, QsciScintilla::STYLE_LINENUMBER,
                        VFunctions::RGB2BGR(_style_map.value("行号").back));
    this->SendScintilla(QsciScintilla::SCI_STYLESETFORE, QsciScintilla::STYLE_LINENUMBER,
                        VFunctions::RGB2BGR(_style_map.value("行号").fore));

    // 折叠栏
    this->setMarginMarkerMask(QsciScintilla::SC_MARGIN_FORE, QsciScintilla::SC_MASK_FOLDERS);
    this->setFoldMarginColors(_style_map.value("折叠栏").back,
                              _style_map.value("折叠栏").back);

    this->markerDefine(QsciScintilla::MarkerSymbol::BoxedMinus, QsciScintilla::SC_MARKNUM_FOLDEROPEN);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDEROPEN);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDEROPEN);

    this->markerDefine(QsciScintilla::MarkerSymbol::BoxedPlus, QsciScintilla::SC_MARKNUM_FOLDER);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDER);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDER);

    this->markerDefine(QsciScintilla::MarkerSymbol::VerticalLine, QsciScintilla::SC_MARKNUM_FOLDERSUB);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDERSUB);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDERSUB);

    this->markerDefine(QsciScintilla::MarkerSymbol::BottomLeftCorner, QsciScintilla::SC_MARKNUM_FOLDERTAIL);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDERTAIL);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDERTAIL);

    this->markerDefine(QsciScintilla::MarkerSymbol::BoxedPlusConnected, QsciScintilla::SC_MARKNUM_FOLDEREND);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDEREND);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDEREND);

    this->markerDefine(QsciScintilla::MarkerSymbol::BoxedMinusConnected, QsciScintilla::SC_MARKNUM_FOLDEROPENMID);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDEROPENMID);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDEROPENMID);

    this->markerDefine(QsciScintilla::MarkerSymbol::VerticalLine, QsciScintilla::SC_MARKNUM_FOLDERMIDTAIL);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDERMIDTAIL);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDERMIDTAIL);

    this->markerDefine(QsciScintilla::MarkerSymbol::BoxedMinus, QsciScintilla::SC_MARKNUM_FOLDEROPEN);
    this->setMarkerForegroundColor(_style_map.value("折叠栏").back, QsciScintilla::SC_MARKNUM_FOLDEROPEN);
    this->setMarkerBackgroundColor(_style_map.value("折叠栏").fore, QsciScintilla::SC_MARKNUM_FOLDEROPEN);

    // 折叠配色
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDEROPEN,VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDER, VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDERSUB, VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDERTAIL,VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDEREND, VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDEROPENMID, VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));
    this->SendScintilla(QsciScintilla::SCI_MARKERSETBACKSELECTED,
        QsciScintilla::SC_MARKNUM_FOLDERMIDTAIL, VFunctions::RGB2BGR(_style_map.value("折叠栏激活状态").fore));

    // 缩进线
    this->setIndentationGuidesForegroundColor(_style_map.value("缩进线").fore);
    this->setIndentationGuidesBackgroundColor(_style_map.value("缩进线").back);

    // 通常背景色
    this->SendScintilla(QsciScintilla::SCI_STYLESETBACK,
        QsciScintilla::STYLE_DEFAULT, VFunctions::RGB2BGR(_style_map.value("默认").back));


    // 插入符号
    this->SendScintilla(QsciScintilla::SCI_SETCARETFORE, VFunctions::RGB2BGR(_style_map.value("插入符号").fore));
    this->SendScintilla(QsciScintilla::SCI_SETCARETLINEBACK,VFunctions::RGB2BGR(_style_map.value("选中行").back));
    qDebug() << "选中行" << _style_map.value("选中行").back;

    // 选择内容样式
    this->setSelectionForegroundColor(_style_map.value("选择文本").fore);
    this->setSelectionBackgroundColor(_style_map.value("选择文本").back);

    // 折叠文本样式
    this->SendScintilla(QsciScintilla::SCI_STYLESETBACK, QsciScintilla::STYLE_FOLDDISPLAYTEXT, VFunctions::RGB2BGR(_style_map.value("折叠文本").back));
    this->SendScintilla(QsciScintilla::SCI_STYLESETFORE, QsciScintilla::STYLE_FOLDDISPLAYTEXT, VFunctions::RGB2BGR(_style_map.value("折叠文本").fore));
    this->SendScintilla(QsciScintilla::SCI_STYLESETFONT, QsciScintilla::STYLE_FOLDDISPLAYTEXT, VGlobal::setting.textedit_font_name.toStdString().data());
    this->SendScintilla(QsciScintilla::SCI_STYLESETSIZE, QsciScintilla::STYLE_FOLDDISPLAYTEXT, VGlobal::setting.textedit_font_size);

//    this->setCaretLineBackgroundColor(QColor(_style_map.value("选中行").back));
}

void VScintillaEx::init_option()
{
    // 设置定时器
    _tip_timer.setSingleShot(true);
    _update_timer.setSingleShot(true);
    _tip_timer.setInterval(VGlobal::setting.intelligence_delay);
    _update_timer.setInterval(200);

    // 设置lexer
    _vlexer.setFoldCompact(false);

    // 设置lexer
    this->setLexer(&_vlexer);

    // 设置行号栏

    this->setMarginType(QsciScintilla::SC_MARGIN_NUMBER, QsciScintilla::NumberMargin);
    this->setMarginLineNumbers(QsciScintilla::SC_MARGIN_NUMBER, true);
    this->setMarginWidth(QsciScintilla::SC_MARGIN_NUMBER, 30);
    this->setUtf8(true);

    // 设置折叠栏
    this->setProperty("fold", "1");
    this->setMarginWidth(QsciScintilla::SC_MARGIN_BACK, 13);
    this->setMarginWidth(QsciScintilla::SC_MARGIN_FORE, 13);
    this->setMarginMarkerMask(QsciScintilla::SC_MARGIN_FORE, QsciScintilla::SC_MASK_FOLDERS);
    this->setMarginSensitivity(QsciScintilla::SC_MARGIN_FORE, true);

    // 设置折叠样式为文本
    this->SendScintilla(QsciScintilla::SCI_FOLDDISPLAYTEXTSETSTYLE, QsciScintilla::SC_FOLDDISPLAYTEXT_BOXED);

    // 设置tab宽度
    this->setTabWidth(VGlobal::setting.tab_width);

    // 设置缩进线
    this->setIndentationGuides(true);

    // 设置突出显示
    this->SendScintilla(QsciScintilla::SCI_MARKERENABLEHIGHLIGHT, true);

    // 设置插入符号
    this->SendScintilla(QsciScintilla::SCI_SETCARETPERIOD, 500);
    this->SendScintilla(QsciScintilla::SCI_SETCARETWIDTH, 2);
    this->SendScintilla(QsciScintilla::SCI_SETCARETLINEVISIBLE, 1);

    // 设置margin点击通知
    this->setMarginSensitivity(QsciScintilla::SC_MARGIN_BACK, true);
    this->setMarginSensitivity(QsciScintilla::SC_MARGIN_NUMBER, true);

    // 设置鼠标悬停500毫秒后发送悬停消息
    this->SendScintilla(QsciScintilla::SCI_SETMOUSEDWELLTIME, 500);

    // ???
    this->SendScintilla(QsciScintilla::SCI_SETMODEVENTMASK, QsciScintilla::SC_MOD_INSERTTEXT| QsciScintilla::SC_MOD_DELETETEXT);
}

void VScintillaEx::init_connect()
{
    QObject::connect(this, &VScintillaEx::SCN_UPDATEUI, this, &VScintillaEx::on_SCN_UPDATEUI);
    QObject::connect(this, &VScintillaEx::SCN_CHARADDED, this, &VScintillaEx::on_SCN_CHARADDED);
    QObject::connect(this, &VScintillaEx::SCN_ZOOM, this, &VScintillaEx::on_SCN_ZOOM);
    QObject::connect(this, &VScintillaEx::linesChanged, this, &VScintillaEx::on_linesChanged);
    QObject::connect(this, &VScintillaEx::selectionChanged, this, &VScintillaEx::on_selectionChanged);
    QObject::connect(this, &VScintillaEx::SCN_NEEDSHOWN, this, &VScintillaEx::on_SCN_NEEDSHOWN);
    QObject::connect(this, &VScintillaEx::SCN_HOTSPOTCLICK, this, &VScintillaEx::on_SCN_HOTSPOTCLICK);
    QObject::connect(this, &VScintillaEx::SCN_DWELLSTART, this, &VScintillaEx::on_SCN_DWELLSTART);
    QObject::connect(this, &VScintillaEx::SCN_DWELLEND, this, &VScintillaEx::on_SCN_DWELLEND);
    QObject::connect(this, &VScintillaEx::modificationChanged, this, &VScintillaEx::on_modificationChanged);
    QObject::connect(this, &VScintillaEx::marginClicked, this, &VScintillaEx::on_marginClicked);;
    QObject::connect(this, &VScintillaEx::SCN_FOCUSOUT, this, &VScintillaEx::on_SCN_FOCUSOUT);
    QObject::connect(this, &VScintillaEx::SCN_FOCUSIN, this, &VScintillaEx::on_SCN_FOCUSIN);
    connect(&_tip_timer, &QTimer::timeout, this, &VScintillaEx::on_tip_timer_timeout);
    connect(&_update_timer, &QTimer::timeout, this, &VScintillaEx::on_update_timer_timeout);
}

void VScintillaEx::on_marginClicked(int margin, int line)
{
    qDebug() << line << margin;
    if (margin == QsciScintilla::SC_MARGIN_FORE)
    {
        this->SendScintilla(QsciScintilla::SCI_TOGGLEFOLDSHOWTEXT, line, (char*)" {...} ");
    }
}

void VScintillaEx::on_SCN_UPDATEUI(int updated)
{
}

void VScintillaEx::on_SCN_ZOOM()
{
    on_linesChanged();
}

void VScintillaEx::on_linesChanged()
{
#if 0
    int string_len = QString::number(this->lines()).length();
	int signal_width = this->textWidth(0, "0");
    int px = (string_len + 2) * signal_width;
    this->setMarginWidth(QsciScintilla::SC_MARGIN_NUMBER, px);
#endif
}

void VScintillaEx::on_selectionChanged()
{
    //modify_testing();
    _update_timer.start();
    // emit update text
    emit signal_hide_tip(VGlobal::TipType::TIP_INPUT|
                         VGlobal::TipType::TIP_PARAMETER|
                         VGlobal::TipType::TIP_MOUSERHOVER);

    emit signal_scintilla_update_info(_path, this->cursorOfLine()+1, this->cursorPos()-this->
                                      lineStartPos(this->cursorOfLine()), this->lines());

    // hide calltip
}

void VScintillaEx::on_SCN_NEEDSHOWN(int i1, int i2)
{
//    qDebug() << i1 << " " << i2;
}

void VScintillaEx::on_SCN_HOTSPOTCLICK(int position, int modifiers)
{
    //    qDebug() << position;
}

void VScintillaEx::on_SCN_CHARADDED(int charadded)
{
    static QString symbols("{}[]()\'\"");
    if (charadded == 13)
    {
        auto_indentation();
        _update_timer.start();
    }
	//this->insertText(this->cursorPos()-1, "\'");
    //else if (symbols.indexOf(QChar(charadded)) != -1)
    //{
    //    symbol_complate(charadded);
    //}

    // input tip
    _tip_timer.start();

//    this->SendScintilla(QsciScintilla::SCI_STARTSTYLING, 0);
//    this->SendScintilla(QsciScintilla::SCI_SETSTYLING, 10, QsciLexerCPP::Keyword);
}

void VScintillaEx::on_modificationChanged(bool m)
{
    if(m && (_modify == false))
    {
        set_modify(true);
//        setModified(false);
    }
}

void VScintillaEx::on_SCN_DWELLEND(int position, int x, int y)
{
    VGlobal::mouse_hover_tip->hide();
}

void VScintillaEx::on_SCN_DWELLSTART(int position, int x, int y)
{
    if (position == -1)
    {
        return;
    }

    QString pre = get_line_text_of_pos_before(position);
    QString next = get_line_text_of_pos_next(position);
    int line = this->posOfLine(position);
    emit signal_mouse_hover_tip(_path, pre, next, line +1,
                                in_function(line), position);
}

void VScintillaEx::on_SCN_FOCUSOUT()
{
    emit signal_hide_tip(VGlobal::TipType::TIP_INPUT|
                         VGlobal::TipType::TIP_PARAMETER|
                         VGlobal::TipType::TIP_MOUSERHOVER);
    modify_testing();
}

void VScintillaEx::on_SCN_FOCUSIN()
{
    emit signal_scintilla_update_info(_path, this->cursorOfLine()+1, this->cursorPos()-this->
                                      lineStartPos(this->cursorOfLine()), this->lines());
}

void VScintillaEx::on_tip_timer_timeout()
{
    input_tip_testing();
    function_parameter_tip();
}

void VScintillaEx::on_update_timer_timeout()
{
    modify_testing();
}

bool VScintillaEx::is_input_file_name(QString text)
{
    if(text.length() == 0)
    {
        return false;
    }

    if(text.at(0) == '#' &&
            (text.indexOf("#include") != -1 ||
                            text.indexOf("#引入") != -1))
    {
        return true;
    }

    return false;
}

int VScintillaEx::get_char_count(QString text, QChar c)
{
    int result = 0;
    for (int i = text.length() - 1; i >= 0; i--)
    {
        if(text.at(i) == c)
            result++;
    }
    return result;
}

QString VScintillaEx::reget_string(QString text, QString ex)
{
    QString result;
    for (int i = text.length() - 1; i >= 0; i--)
    {
        QChar c = text.at(i);
        if (c.isLetter() || c.unicode() > 127 || c == '_' || c.isDigit() || ex.indexOf(c) != -1)
        {
            result = c + result;
        }
        else
        {
            break;
        }
    }
    return result;
}

void VScintillaEx::set_modify(bool m)
{
    //emit signal_modificationChanged(_path, m);
    if(m)
    {
        emit signal_set_title(QFileInfo(_path).fileName() + "*");
    }
    else
    {
        emit signal_set_title(QFileInfo(_path).fileName());
    }
    _modify = m;
}

void VScintillaEx::input_tip_testing()
{

    int cursor_pos = this->cursorPos();
    if (cursor_pos < 0)
    {
        return;
    }

    QString line_text = get_line_text_of_pos_before(cursor_pos);

    // 判断是否是 #include
    if(is_input_file_name(line_text))
    {
        QString str = reget_string(line_text, "/.- ");

        if(get_char_count(line_text, '\"') == 1)
        {
            emit signal_file_tip(_path, str);
        }
        else
        {
            emit signal_file_tip(_path, "");
        }

    }
    else
    {
        emit signal_inpout_tip(_path, line_text, this->cursorOfLine(), in_function(this->cursorOfLine()));
    }
}

void VScintillaEx::function_parameter_tip()
{
    if (this->lineFoldLevel(this->cursorOfLine()) <= 1024)
    {
        return;
    }

    int cursor_pos = this->cursorPos();
    int n = -1;
    int parameter_pos = 0;
    for (int i = cursor_pos; i >= 0; i--)
    {
        int style = this->SendScintilla(QsciScintilla::SCI_GETSTYLEAT, i - 1);
        QString str = this->text(i - 1, i);
        if (style == 10 || style == 127 || style == 0)
        {
            if (str == "(")
            {
                n++;
            }
            else if (str == ")")
            {
                n--;
            }
            else if (str == "," && n == -1)
            {
                parameter_pos++;
            }
            else if (str == ";" || str == "{")
            {
                break;
            }

            if (n == 0)
            {
                QString function_name = input_block(i - 1);
                if (function_name.length() != 0)
                {
                    emit signal_function_parameter_tip(_path, function_name, parameter_pos, i);
                    return;
                }
            }
        }
    }

    emit signal_hide_tip(VGlobal::TipType::TIP_PARAMETER);
}

QString VScintillaEx::input_block(int pos)
{
    QString result;
    int cursor_pos = 0;
    if (pos == -1)
    {
        cursor_pos = this->cursorPos();
    }
    else
    {
        cursor_pos = pos;
    }

    int cursor_line = this->posOfLine(cursor_pos);
    int line_start = this->SendScintilla(QsciScintilla::SCI_POSITIONFROMLINE, cursor_line);
    if (cursor_pos < 0)
    {
        return result;
    }

    QString line_text = this->text(line_start, cursor_pos);
    for (int i = line_text.length() - 1; i >= 0; i--)
    {
        QChar c = line_text.at(i);
        if (c.isLetter() || c.unicode() > 127 || c == '_' || c.isDigit())
        {
            result = c + result;
        }
        else
        {
            break;
        }
    }
    return result;
}

void VScintillaEx::auto_indentation()
{
    // ???????????е?????
    int cursor_pos = this->cursorPos();
    int cursor_of_line = this->cursorOfLine();
    QString line_text = this->text(cursor_of_line);
    int fold_level = this->lineFoldLevel(cursor_of_line);
    if (fold_level > 1024)
    {
        this->setIndentation(cursor_of_line, (fold_level - 1024)*this->tabWidth());
        cursor_pos = this->cursorPos();
        int line_start = this->SendScintilla(QsciScintilla::SCI_POSITIONFROMLINE, cursor_of_line);
        if (cursor_pos < line_start + (fold_level - 1024)*this->tabWidth())
        {
            this->setCursorPosition(cursor_of_line, fold_level - 1024);
        }
    }

    // ???????м??????????
    QString preLineText = this->text(cursor_of_line - 1).trimmed();
    if (!line_text.isEmpty() && !preLineText.isEmpty() &&
        preLineText.at(preLineText.count() - 1) == '{' && line_text.at(0) == '}')
    {
        this->insert("\r\n");
        this->setIndentation(cursor_of_line + 1, (fold_level - 1024)* this->tabWidth());
        fold_level = (this->SendScintilla(QsciScintilla::SCI_GETFOLDLEVEL, cursor_of_line))&(QsciScintilla::SC_FOLDLEVELNUMBERMASK);
        fold_level++;
        if (fold_level > 1024)
        {
            this->setIndentation(cursor_of_line, (fold_level - 1024)* this->tabWidth());
            int cursorPos = this->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
            int lineStart = this->SendScintilla(QsciScintilla::SCI_POSITIONFROMLINE, cursor_of_line);
            if (cursorPos < lineStart + (fold_level - 1024)* this->tabWidth())
            {
                this->setCursorPosition(cursor_of_line, (fold_level - 1024));
            }
        }

    }
}

void VScintillaEx::symbol_complate(int c)
{
    switch (c)
    {
    case '{':
        this->insertText(this->cursorPos(), "}");
        return;
    case '[':
        this->insertText(this->cursorPos(), "]");
        return;
    case '(':
        this->insertText(this->cursorPos(), ")");
        return;
    case '\'':
		
        if (symbol_delete(c) == false)
        {
			int temp = this->cursorPos();
            this->insertText(this->cursorPos(), "\'");
        }
        break;
    case '\"':
        if (symbol_delete(c) == false)
        {
            this->insertText(this->cursorPos(), "\"");
        }
        break;
    default:
        break;
    }

    switch (c)
    {
    case '}':
    case ']':
    case ')':
        symbol_delete(c);
        break;
    default:
        break;
    }
}

bool VScintillaEx::symbol_delete(int c)
{
    if (this->cursorPos() < this->lineEndPos(this->cursorOfLine()))
    {
        QString s = this->text(this->cursorPos(), this->cursorPos() + 1);
        if (c == s.at(0).unicode())
        {
            this->deleteRange(this->cursorPos(), 1);
            return true;
        }
    }
    return false;
}

bool VScintillaEx::in_function(int line)
{
    return this->lineFoldLevel(line)>1024;
}

QString VScintillaEx::get_line_text_of_pos_before(int pos)
{
    if(pos < 0)
    {
        return "";
    }

    int cursor_line = this->posOfLine(pos);
    int line_start = this->lineStartPos(cursor_line);
    QString result = this->text(line_start, pos);
    return result;
}

QString VScintillaEx::get_line_text_of_pos_next(int pos)
{
    if(pos < 0)
    {
        return "";
    }

    int cursor_line = this->posOfLine(pos);
    int line_end = this->lineEndPos(cursor_line);
    QString result = this->text(pos, line_end);
    return result;
}

// 会自动判断是否在输入文件名称
// 如果是在输入文件名称
// 会自动将 . 包含进去
QString VScintillaEx::get_input_block()
{
    int cursor_pos = this->cursorPos();
    if (cursor_pos < 0)
    {
        return "";
    }
    QString line_text = get_line_text_of_pos_before(cursor_pos);
    if(is_input_file_name(line_text))
    {
        return reget_string(line_text, ".");
    }
    else
    {
        return reget_string(line_text, "");
    }
}

void VScintillaEx::contextMenuEvent(QContextMenuEvent *)
{
    _content_menu.clear();
    _content_menu.addAction(VGlobal::action.value("jump"));
    _content_menu.addSeparator();
    _content_menu.addAction(VGlobal::action.value("copy"));
    _content_menu.addAction(VGlobal::action.value("cut"));
    _content_menu.addAction(VGlobal::action.value("paste"));
    _content_menu.addSeparator();
    _content_menu.addAction(VGlobal::action.value("comment"));
    _content_menu.addAction(VGlobal::action.value("uncomment"));
    _content_menu.addSeparator();
    _content_menu.addMenu(&_expand_menu);
    _content_menu.exec(QCursor::pos());
}

bool VScintillaEx::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == this->viewport() || watched == this)
    {
        static QString symbols("{[(\'\"");
        if (event->type() == QKeyEvent::KeyPress)
        {
            QKeyEvent* key_event = reinterpret_cast<QKeyEvent*>(event);
            if (key_event->key() == Qt::Key_Backspace)
            {
                //int cursor_pos = this->cursorPos();
                //if (cursor_pos > 0)
                //{
                //    QString fore_string = this->text(cursor_pos - 1, cursor_pos);
                //    if (symbols.indexOf(fore_string) != -1)
                //    {
                //        int unicode = fore_string.at(0).unicode();
                //        switch (unicode)
                //        {
                //        case '{':
                //            symbol_delete('}');
                //            break;
                //        case '[':
                //            symbol_delete(']');
                //            break;
                //        case '(':
                //            symbol_delete(')');
                //            break;
                //        case '\'':
                //            symbol_delete('\'');
                //            break;
                //        case '\"':
                //            symbol_delete('\"');
                //            break;
                //        default:
                //            break;
                //        }
                //    }
                //}
            }
            else if(key_event->key() == Qt::Key_Return ||
                    key_event->key() == Qt::Key_Enter)
            {

                int line  = (this->cursorOfLine()+2) > this->lines() ?
                            this->lines() : (this->cursorOfLine()+2);
                int line_end_pos = this->lineEndPos(line);
                QString text = this->text(this->cursorPos(), line_end_pos);

                QRegularExpression reg;
                reg.setPattern("/\\*-.*?-\\*/");
                if(reg.match(text).hasMatch())
                {
                    VGlobal::input_tip->hide();

                    this->findFirst("/\\*-.*?-\\*/", true, false, false, true);
                    if(this->selectedText() == "/*--*/")
                    {
                        this->replaceSelectedText("");
                    }
                    return true;
                }
            }

            if(VGlobal::input_tip->isVisible())
            {
                if(key_event->key() == Qt::Key_Tab)
                {
                    VWords* ptr = (VWords*)(VGlobal::input_tip->currentItem()->data(Qt::UserRole).value<void*>());
                    if(ptr != nullptr)
                    {
                        qDebug() << ptr->_name;
                        emit signal_select_word(_path, new VWords(ptr));

                        // 删除当前提示的内容
                        QString input= get_input_block();
                        qDebug() << "input" << input;
                        int input_length = input.toStdString().length();

                        int cursor_pos = this->cursorPos();
                        this->setSelect(cursor_pos - input_length, cursor_pos);
                        this->replaceSelectedText("");
//                        VGlobal::input_tip->hide();

//                        return true;

                        if(ptr->_kind == VWords::KIND::TEMPLATE)
                        {
                            int tab_count = this->indentation(this->cursorOfLine()) / this->tabWidth();
                            qDebug() << tab_count;
                            QString s_pre;
                            while(tab_count--)
                            {
                                s_pre += '\t';
                            }

                            qDebug() << s_pre;
                            QString s_template = ptr->_signature;
                            s_template = s_template.replace("<br>", "\r\n" + s_pre);
                            this->insert(s_template);
                            this->findFirst("/\\*-.*?-\\*/", true, false, false, true);
                            if(this->selectedText() == "/*--*/")
                            {
                                this->replaceSelectedText("");
                            }

//                            VGlobal::input_tip->hide();
                            emit signal_hide_tip(VGlobal::TipType::TIP_INPUT);
                            return true;
                        }
                        else
                        {
                            this->replaceSelectedText(ptr->_name);
//                            VGlobal::input_tip->hide();
                            emit signal_hide_tip(VGlobal::TipType::TIP_INPUT);
                            return true;
                        }
                    }
                }
                else if(key_event->key() == Qt::Key_Up)
                {
                    if (VGlobal::input_tip->currentRow() > 0)
                    {
                        VGlobal::input_tip->setCurrentRow(VGlobal::input_tip->currentRow() - 1);
                    }
                    else
                    {
                        VGlobal::input_tip->setCurrentRow(VGlobal::input_tip->count() - 1);
                    }
                    return true;
                }
                else if(key_event->key() == Qt::Key_Down)
                {
                    if (VGlobal::input_tip->currentRow() < VGlobal::input_tip->count() - 1)
                    {
                        VGlobal::input_tip->setCurrentRow(VGlobal::input_tip->currentRow() + 1);
                    }
                    else
                    {
                        VGlobal::input_tip->setCurrentRow(0);
                    }
                    return true;
                }
            }
        }
        else if (event->type() == QKeyEvent::KeyRelease)
        {

            QKeyEvent* key_event = (QKeyEvent*)event;
            if (key_event->key() == Qt::Key_Backspace)
            {
                _tip_timer.start();
//                input_tip_testing();
            }
            else if(key_event->key() == Qt::Key_Escape)
            {
                emit signal_hide_tip(VGlobal::TipType::TIP_INPUT|
                                     VGlobal::TipType::TIP_PARAMETER|
                                     VGlobal::TipType::TIP_MOUSERHOVER);
                return false;
            }

        }
        else if(event->type() == QEvent::Wheel && VGlobal::input_tip->isVisible())
        {
            emit signal_hide_tip(VGlobal::TipType::TIP_INPUT|
                                 VGlobal::TipType::TIP_PARAMETER|
                                 VGlobal::TipType::TIP_MOUSERHOVER);
        }
        else if (event->type() == QEvent::MouseButtonRelease)
        {
            // 跳转到定义/声明
            QMouseEvent *mouse_e = (QMouseEvent*)event;
            qDebug() << mouse_e->button();
            if (mouse_e->button() == Qt::LeftButton)
            {
                QKeyEvent *key_e = (QKeyEvent*)event;
                if (key_e->modifiers() & Qt::ControlModifier)
                {
                    if(this->cursorPos() == this->anchorPos())
                    {
                        this->jump_request();
                    }
                }

                // 记录导航信息
                emit signal_append_navigation(_path, this->cursorOfLine(), this->cursorPos());
            }
            else if(mouse_e->button() == Qt::BackButton)
            {
                VGlobal::action.value("retreat")->triggered();
            }
            else if(mouse_e->button() == Qt::ForwardButton)
            {
                VGlobal::action.value("advance")->triggered();
            }
        }
    }
    return VScintillaBase::eventFilter(watched, event);
}

void VScintillaEx::modify_testing()
{
    if(this->isModified())
    {
        emit signal_update_file_text(_path, this->text());
        this->setModified(false);
    }
}

void VScintillaEx::reload_setting()
{
    init_setting();
    init_option();
    init_color();
}

void VScintillaEx::update_text()
{
    emit signal_update_file_text(_path, this->text());
}

void VScintillaEx::rename(QString path)
{
    _path = path;
    set_modify(_modify);
}

